package com.fastwire.carriere.common.entity;

import java.io.ByteArrayInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.fastwire.carriere.common.constant.AppConstants;
import com.fastwire.carriere.common.util.CommonLogger;
import com.fastwire.carriere.common.util.DateUtil;
import com.fastwire.carriere.common.util.ReflectionUtil;
import com.fastwire.carriere.common.util.StringUtil;

// TODO: Auto-generated Javadoc
/**
 * The Class BaseObject.
 */
public abstract class BaseObject {

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		StringBuffer stringBuffer = new StringBuffer();
		Class currentClass = this.getClass();

		try {
			do {

				Field[] fields = currentClass.getDeclaredFields();

				for (int index = 0; index < fields.length; index++) {

					fields[index].setAccessible(true);

					stringBuffer.append(fields[index].getName() + " is:");

					stringBuffer.append(fields[index].get(this) + " ");

				}

				currentClass = currentClass.getSuperclass();
			}

			while (currentClass != null);
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return stringBuffer.toString();
	}

	/**
	 * To xml.
	 *
	 * @param dataElement the data element
	 */
	public void toXML(Element dataElement) {

		Class currentClass = this.getClass();

		Element networkentity = dataElement.addElement(currentClass
				.getSimpleName());

		try {
			do {

				Field[] fields = currentClass.getDeclaredFields();

				for (int index = 0; index < fields.length; index++) {

					fields[index].setAccessible(true);
					if (fields[index].getType().equals(String.class)) {

						String fieldvalue = (String) fields[index].get(this);
						networkentity
								.addElement(fields[index].getName())
								.setText(
										StringUtil.isEmptyString(fieldvalue) ? ""
												: fieldvalue);
					}

				}

				currentClass = currentClass.getSuperclass();
			}

			while (currentClass != null);
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * To xml.
	 *
	 * @return the string
	 */
	public String toXML() {

		Document document = DocumentHelper.createDocument();

		Element networkentity = document.addElement(AppConstants.DATA_ELEMENT);

		toXML(networkentity);
		return document.asXML();
	}

	/**
	 * Load data.
	 *
	 * @param classElement the class element
	 */
	public void loadData(Element classElement) {

		Class currentClass = this.getClass();

		try {

			Iterator<Element> iterator = classElement.elementIterator();
			Field[] fields = currentClass.getDeclaredFields();
			while (iterator.hasNext()) {
				Element element = iterator.next();

				for (Field field : fields) {

					if (element.getName().equalsIgnoreCase(field.getName())) {
						field.setAccessible(true);
						if (field.getType().equals(String.class)) {

							field.set(this, element.getText());

						} else if (field.getType().equals(Date.class)) {

							field.set(this, DateUtil.parseDate(
									DateUtil.DATE_SLASH, element.getText()));
						} else if (field.getType().equals(List.class)) {

							@SuppressWarnings("rawtypes")
							List fieldList = (List) field.get(this);
							ParameterizedType type = (ParameterizedType) field
									.getGenericType();
							Iterator<Element> itemIterator = element
									.elementIterator();
							while (itemIterator.hasNext()) {

								Element itemElement = itemIterator.next();
								Class classDefinition = Class
										.forName(ReflectionUtil.getSimpleClassName(type
												.getActualTypeArguments()[0]
												.toString()));
								BaseObject object = (BaseObject) classDefinition
										.newInstance();
								object.loadData(itemElement);

								fieldList.add(object);

							}

						} else if (BaseObject.class.equals(field.getType()
								.getSuperclass())) {

							BaseObject baseObject = (BaseObject) Class.forName(
									field.getType().getName()).newInstance();
							if (element.elements() != null
									&& element.elements().size() > 0) {
								baseObject.loadData((Element) element
										.elements().get(0));
								field.set(this, baseObject);
							}

						}
					}

				}
			}

		}

		catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			CommonLogger.error(this, e.getMessage());
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			CommonLogger.error(this, e.getMessage());
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * Load data.
	 *
	 * @param inputString the input string
	 */
	public void loadData(String inputString) {

		SAXReader reader = new SAXReader();

		try {

			Document doc = reader.read(new ByteArrayInputStream(inputString
					.getBytes("UTF-8")));
			Element root = doc.getRootElement();
			Element classElement = (Element) root.elements().get(0);

			loadData(classElement);

		} catch (UnsupportedEncodingException e1) {

			e1.printStackTrace();
			CommonLogger.error(this, e1.getMessage());
		} catch (DocumentException e1) {

			e1.printStackTrace();
			CommonLogger.error(this, e1.getMessage());
		}

		catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			CommonLogger.error(this, e.getMessage());
		}
	}

    /**
     * Save to csv.
     * 
     * @param writer the writer
     */
    public void toCSV(FileWriter writer)
    {
        try
        {
            writer.append("\n");
            Class currentClass = this.getClass();

            do
            {
                Field[] fields = currentClass.getDeclaredFields();
                CommonLogger.debug(this, "current class is" + currentClass.getName() + ", it has "
                        + fields.length + " attributs");
                for (int index = 0; index < fields.length; index++)
                {
                    fields[index].setAccessible(true);
                    if (fields[index].getType().equals(String.class))
                    {
                        writer.append((String) fields[index].get(this));
                        writer.append(",");

                    }
                }

                currentClass = currentClass.getSuperclass();
            }

            while (currentClass != null);
        }
        catch (IllegalArgumentException e)
        {
            CommonLogger.error(this, e.getMessage());
        }
        catch (IOException e)
        {
            CommonLogger.error(this, e.getMessage());
        }
        catch (IllegalAccessException e)
        {
            CommonLogger.error(this, e.getMessage());
        }

    }

}
